#include "../include/fsext.h"
#include "../include/buffer.h"
#include "../include/ptrlist.h"
#include "../include/file.h"
#include "../include/state.h"
#include "../include/winapi.h"
#include "../include/macro_file_type.h"
#include "../include/macro_direntry.h"
#include "../include/macro_report.h"

void FsExt::scanDirInBlocks(ParaForShare* para) const
{
	ParaForScanDir* para_for_scandir=static_cast<ParaForScanDir*>(para);
	if(!isBlockValid(para_for_scandir->block_num))
		return;
	uint32 number_of_read_byte=para_for_scandir->block_count*block_size;
	Buffer buffer(number_of_read_byte);
	readBlocks(para_for_scandir->block_num,buffer,para_for_scandir->block_count);
	uint32 next = 0;
	while (true)
	{
		File* file=new File(buffer.data()+next);
		if(file->dir_entry.inode_num!=0)
		{
			para_for_scandir->files->push(file);
			file->inode=readInode(file->dir_entry.inode_num);
		}
		else
			delete file;
		next+=ENTRY_LENGTH(buffer.data()+next);
		if (next >=number_of_read_byte)
			break;
	}
}

void FsExt::checkDirInBlocks(ParaForShare* para) const
{
	ParaForCheckDir* para_for_checkdir=static_cast<ParaForCheckDir*>(para);
	if(!isBlockValid(para_for_checkdir->block_num))
		return;
	uint32 number_of_read_byte=para_for_checkdir->block_count*block_size;
	Buffer buffer(number_of_read_byte);
	readBlocks(para_for_checkdir->block_num,buffer,para_for_checkdir->block_count);
	uint8* start=buffer.data();
	uint32 next=0;
	if(HAVE_FIRST_DEFAULT_ENTRY(start))
	{
		next+=FIRST_DEFAULT_ENTRY_LENGTH+SECOND_DEFAULT_ENTRY_LENGTH(start);
		if (next >=number_of_read_byte)
			return;
	}
	while(true)
	{
		if(TYPE(start+next)==DIR_ENTRY_FILE_TYPE_DIR)
			throw(true);
		next+=ENTRY_LENGTH(start+next);
		if (next >=number_of_read_byte)
			break;
	}
}

void FsExt::findFileInBlocks(ParaForShare* para) const
{
	ParaForFindFile* para_for_findfile=static_cast<ParaForFindFile*>(para);
	if(!isBlockValid(para_for_findfile->block_num))
		return;
	uint32 number_of_read_byte=para_for_findfile->block_count*block_size;
	Buffer buffer(number_of_read_byte);
	readBlocks(para_for_findfile->block_num,buffer,para_for_findfile->block_count);
	uint32 next = 0;
	while (true)
	{
		DirEntry tmp(buffer.data()+next);
		if(tmp.file_name==*(para_for_findfile->file_name))
			throw tmp.inode_num; 
		next+=ENTRY_LENGTH(buffer.data()+next);
		if(next>=number_of_read_byte)
			break;
	}
}

void FsExt::copyFileInBlocks(ParaForShare* para) const
{
	State::state().checkCancel();
	ParaForCopyFile* para_for_copyfile=static_cast<ParaForCopyFile*>(para);
	if(!isBlockValid(para_for_copyfile->block_num))
		return;
	DWORD number_of_write_byte=block_size*para_for_copyfile->block_count;
	Buffer buffer(number_of_write_byte);
	readBlocks(para_for_copyfile->block_num,buffer,para_for_copyfile->block_count);
	if(!(para_for_copyfile->file_block_count-=para_for_copyfile->block_count))
		number_of_write_byte=block_size*(para_for_copyfile->block_count-1)+(para_for_copyfile->pinode->fileSize()%block_size);
	WinAPI::writeData(para_for_copyfile->hfile,buffer,number_of_write_byte);
	State::state().reportBlockCount(PROG_COPYED_BLOCK_COUNT,para_for_copyfile->block_count);
}

void FsExt::scanDirWithRecursionInBlocks(ParaForShare* para) const
{
	ParaForScanDirWithRecursion* para_for_scandir=static_cast<ParaForScanDirWithRecursion*>(para);
	if(!isBlockValid(para_for_scandir->block_num))
		return;
	uint32 number_of_read_byte=para_for_scandir->block_count*block_size;
	Buffer buffer(number_of_read_byte);
	readBlocks(para_for_scandir->block_num,buffer,para_for_scandir->block_count);
	uint32 next = 0;
	uint8* start=buffer.data();
	if(HAVE_FIRST_DEFAULT_ENTRY(start))
	{
		para_for_scandir->files->push(new File(start));
		next+=FIRST_DEFAULT_ENTRY_LENGTH;
		para_for_scandir->files->push(new File(start+next));
		next+=SECOND_DEFAULT_ENTRY_LENGTH(start);
		if (next >=number_of_read_byte)
			return;
	}
	while (true)
	{
		File* file=new File(start+next);
		para_for_scandir->files->push(file);
		file->inode=readInode(file->dir_entry.inode_num);
		switch(file->inode.fileType())
		{
		case INODE_FILE_TYPE_NORMAL:
			{
				uint64 file_size=file->inode.fileSize();
				*(para_for_scandir->file_block_count)+=file_size/block_size;
				if((file_size!=0&&file_size<block_size)||file_size%block_size!=0)
					(*(para_for_scandir->file_block_count))++;
				break;
			}
		case INODE_FILE_TYPE_DIR:
			file->sub_dir=scanDirWithRecursion(file->inode,para_for_scandir->file_block_count);
			break;
		default:
			;
		}
		next+=ENTRY_LENGTH(start+next);
		if (next >=number_of_read_byte)
			break;
	}
}